#include "Map.h"

Map::Map(std::string infoFilename, std::string mapFilename, SDL_Surface* tileSheet) {
	good = false;
	this->tileSheet = NULL;
	this->mapHeight = 50;
	this->mapWidth = 50;
	this->cellHeight = 64;
	this->cellWidth = 64;
	initMap(infoFilename, mapFilename, tileSheet);
}

void Map::initMap(std::string infoFilename, std::string mapFilename, SDL_Surface* tileSheet) {
	this->tileSheet = tileSheet;
	std::ifstream infoFile;
	std::ifstream mapFile;

	infoFile.open(infoFilename.c_str());
	mapFile.open(mapFilename.c_str());

	//Read in information about the map
	if (infoFile.good()) {
		std::string line;
		std::vector<std::string> tokens;
		std::getline(infoFile, line);

		//Process map demensions
		tokens = this->tokenize(line, ',');
		this->mapWidth = std::atoi(tokens[1].c_str());
		this->mapHeight = std::atoi(tokens[2].c_str());

		//Process the entities
		std::getline(infoFile, line);
		tokens = this->tokenize(line, ',');
		while (tokens[0] != "tiles") {
			std::string entityName = tokens[0];
			int entityX = std::atoi(tokens[1].c_str());
			int entityY = std::atoi(tokens[2].c_str());

			//TO IMPLEMENT: ACTUALLY MAKE THE ENTITIES
			if (entityName == "Player_Start") {
				Player* p = new Player(entityX * cellWidth, entityY * cellHeight, NULL);
				p->setName(entityName);
				entities.push_back(p);
			}

			//read in next line
			std::getline(infoFile, line);
			tokens = this->tokenize(line, ',');
		}

		//Process the Tiles
		if (tokens[0] == "tiles") {
			while (std::getline(infoFile, line)) {
				tokens = this->tokenize(line, ',');
				Cell c = Cell(std::atoi(tokens[0].c_str()), std::atoi(tokens[1].c_str()), std::atoi(tokens[2].c_str()), (tokens[3] == "0") ? false : true);
				cells.push_back(c);
			}
		}
	}

	//Resize the mapGrid vectors to hold the map
	mapGrid.resize(mapHeight);
	for (int i = 0; i < mapHeight; i++) {
		mapGrid[i].resize(mapWidth);
	}

	//Read in the actual map
	if (mapFile.good()) {
		std::string line;
		std::getline(mapFile, line);
		std::vector<std::string> tokens;
		int numCells = (tileSheet->h / cellHeight) * (tileSheet->w / cellWidth);
		int y = 0;
		while (std::getline(mapFile, line)) {
			if (line != "") { //make sure there is information of the line
				tokens = this->tokenize(line, ',');

				for (int x = 0; x < 150; x++) {
					int tileNum = atoi(tokens[x].c_str());
					if (tileNum > 0 && tileNum <= numCells) {
						tileNum--; //file indexes at 1, data structure indexes at 0
						mapGrid[y][x] = &cells[tileNum];
					}
				}
			}
			y++;
		}
	}

	if (tileSheet != NULL) {
		good = true;
	}
}

Renderable::Direction Map::checkMapCollision(Renderable* entity) {
	double xPos = entity->getXPos();
	double yPos = entity->getYPos();
	int w = entity->getTexture()->w;
	int h = entity->getTexture()->h;

	SDL_Rect a = SDL_Rect();
	a.x = (int)xPos;
	a.y = (int)yPos;
	a.h = h;
	a.w = w;

	for (int x = 0; x < mapWidth; x++) {
		for (int y = 0; y < mapHeight; y++) {
			Cell* cell = getCell(x, y);
			if (cell->isPassable() == false) { //if the cell is passable I don't care if the entity is in it
				SDL_Rect t = SDL_Rect();
				t.x = x * cellWidth;
				t.y = y * cellHeight;
				t.h = cellHeight;
				t.w = cellWidth;
				Renderable::Direction dir;
				if ((dir = collisionCheck(a, t)) != Renderable::NONE) {
					return dir;
				}
			}
		}
	}
}

Renderable::Direction Map::collisionCheck(SDL_Rect a, SDL_Rect b) {
	int leftA, leftB;
	int rightA, rightB;
	int topA, topB;
	int bottomA, bottomB;

	//Calculate the sides of A  // Should be the entity
	leftA = a.x;
	rightA = a.x + a.w;
	topA = a.y;
	bottomA = a.y + a.h;

	//Calculate sides of B     // Should be a map tile
	leftB = b.x;
	rightB = b.x + b.w;
	topB = b.y;
	bottomB = b.y + b.h;

	//If any of the sides from A are outside of B
	/*if ((topA > topB && topA < bottomB) || (bottomA < bottomB && bottomA > topB)) {
		if ((leftA > leftB && leftA < rightB) || (rightA < rightB && rightA > leftB)) {
			return true;
		}
		return false;
	}
	else {
		return false;
	}*/
    
	if (topA > topB && topA < bottomB) { // TOP
		return Renderable::TOP;
	}
	if (bottomA < bottomB && bottomA > topB) { // BOTTOM
		return Renderable::BOTTOM;
	}

	if (leftA > leftB && leftA < rightB) {
		return Renderable::LEFT;
	}
	if (rightA < rightB && rightA > leftB) {
		return Renderable::RIGHT;
	}

	return Renderable::NONE;
}

std::vector<std::string> Map::tokenize(std::string str, char dilim) {
	std::string word;
	std::vector<std::string> tokens;
	std::stringstream stream(str);
	while (std::getline(stream, word, dilim)) {
		tokens.push_back(word);
	}
	return tokens;
}